feat(ai.agents): native Azure Bot + Teams channel for activity-protocol agents#8939
feat(ai.agents): native Azure Bot + Teams channel for activity-protocol agents#8939v1212 wants to merge 18 commits into
Conversation
…ol agents Provision the Azure Bot and Microsoft Teams channel for activity-protocol (Teams) hosted agents natively during `azd deploy`, replacing the setup-instance-bot.ps1 postdeploy script. The bot is bound to the agent instance identity (msaAppId = instance identity client id), enabled on the Teams channel, and its messaging endpoint is pointed at the agent's activity protocol endpoint. Teardown deletes the bot so its globally unique name is freed for redeploys. Non-activity agents are completely unaffected (single gate on the activity profile). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extend the init-from-local-code path so activity-protocol agents can be initialized without a manifest, producing an azure.yaml identical to the init-from-manifest path and fully satisfying azd deploy. - add activity_protocol/v1 to knownProtocols (opt-in via --protocol or interactive multiselect; no-prompt default unchanged: responses/2.0.0) - inject activity agentEndpoint (protocols: [activity], authorizationSchemes: [BotServiceRbac]) when IsActivityProtocol matches, so postdeploy bot gate fires for code-initialized activity agents just like manifest agents - add validateProtocolSelection to reject combining activity_protocol with other protocols (activity agent exposes only the activity endpoint); enforced in both flag and interactive paths - add ActivityAgentEndpoint helper + unit tests The azd init flow is otherwise unchanged for non-activity agents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- go fix: use new(x) for pointer-to-value and range-over-int (go 1.26) in botservice.go / botservice_test.go - cspell: add activity/bot terms (botservice, armbotservice, Azurebot, idempotently, sideload, behaviour) to the extension dictionary Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eploy Replace the sample-specific, console-only Teams next-steps hint with a generic TEAMS_APP_SETUP.md written next to the agent source during postdeploy. The guide is built only from runtime values (agent name, bot name, msaAppId) and links to official Microsoft Learn docs for packaging and sideloading a Teams app, so it works for any activity agent regardless of source (init-from-manifest or init-from-code) and is a no-op for non-activity deployments. Writing a file (not stdout) guarantees the user reliably receives the guidance, since azd's progress UI does not surface postdeploy handler stdout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address peer-review feedback on the activity-protocol bot flow: - Salt the Azure Bot resource name with a hash of the deployment scope (subscription + resource group). BotService names are globally unique, so two environments deploying an agent with the same name previously collided; the name stays deterministic per scope so redeploys still update the same bot. Long agent names are truncated to the BotService handle limit. Create and teardown share BotScopeSalt so the names match. - On postdeploy bot-config failure, make the error state that the agent version deployed successfully and only the Teams channel binding failed (commonly permissions/quota), and to re-run 'azd deploy'. - Rename TestEnsureBotIsIdempotentAcrossRuns to TestEnsureBotIssuesUpsertOnEveryRun and clarify it asserts an upsert each run, not server-side idempotency; expand TestBotName to cover determinism, per-scope uniqueness, and length capping. - Clarify the messaging-endpoint api-version constant is intentionally independent of the deploy api-version. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d guide Rewrite the generated TEAMS_APP_SETUP.md to include direct, minimal steps instead of only linking out: an easiest path (Teams Developer Portal, reuse the existing Azure bot by Bot ID, download a ready .zip) and a by-hand path (three-file list, a copy-paste minimal manifest.json noting that app id is a new GUID distinct from botId), plus numbered sideload steps (Apps -> Manage your apps -> Upload an app -> Upload a custom app). Each step keeps a link to the official Microsoft Learn doc for detail. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… fallback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…l-simple # Conflicts: # cli/azd/extensions/azure.ai.agents/internal/cmd/listen.go
There was a problem hiding this comment.
Pull request overview
This PR adds native azd support for provisioning the Azure Bot and Microsoft Teams channel that front an activity-protocol (Teams) hosted agent, replacing the previous setup-instance-bot.ps1 / post-deploy.ps1 postdeploy scripts. Bot provisioning is wired into the azure.ai.agents extension's postdeploy/postdown lifecycle handlers, and all Teams/bot-specific behavior sits behind a single activity-profile gate so non-activity agents are unaffected. It also extends the init-from-code path to support activity_protocol so it produces an azure.yaml identical to the manifest path.
Changes:
- New
botservicepackage (create/update Azure Bot, enable Teams channel, delete on teardown) with narrow SDK interfaces for fake-backed unit tests. - New activity-profile gate (
IsActivityProtocol/ResolveActivityProfile) and postdeploy/postdown hooks (ensureActivityBot/teardownActivityBots) plus a generatedTEAMS_APP_SETUP.mdguide. init-from-codenow recognizesactivity_protocol/v1, injects the activityagentEndpoint, and rejects combining it with other protocols.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
internal/project/activity_profile.go (+test) |
Single gate detecting activity opt-in and the injected activity endpoint declaration. |
internal/pkg/botservice/botservice.go (+test) |
Azure Bot create-or-update, Teams channel enable, delete, deterministic naming/messaging endpoint. |
internal/cmd/listen.go |
Wires ensureActivityBot into postdeploy and teardownActivityBots into postdown. |
internal/cmd/listen_activity.go (+test) |
Bot provisioning/teardown handlers, next-steps output, and Teams setup guide generation. |
internal/cmd/init_from_code.go (+test) |
Adds activity_protocol, injects activity endpoint, enforces protocol exclusivity. |
go.mod / go.sum |
Adds armbotservice v1.2.0 (verified to exist). |
cspell.yaml |
Adds bot/Teams-related dictionary terms. |
Findings are limited to a misleading bots[].id reference (should be bots[].botId) in the user-facing next-steps message and matching test comment, a errors.As → errors.AsType convention nit, and a British-spelling ("behaviour") consistency nit. The core provisioning logic, gating, idempotency, and teardown look correct and are backed by unit tests and the described live E2E validation.
…avior spelling - Fix runtime/test message to reference Teams manifest bots[].botId (not bots[].id) - Use Go 1.26 errors.AsType helper in botservice.isNotFound for consistency - Use American spelling 'behavior' and drop the cspell behaviour allow-entry Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio
left a comment
There was a problem hiding this comment.
Activity-protocol bot provisioning is well-gated behind IsActivityProtocol, idempotent via PUT, and correctly scoped to Phase 1 (simple use case). Teardown is properly best-effort. Test coverage looks solid across botservice, activity_profile, and init_from_code paths.
| var knownProtocols = []protocolInfo{ | ||
| {Name: "responses", Version: "2.0.0"}, | ||
| {Name: "invocations", Version: "1.0.0"}, | ||
| {Name: "activity_protocol", Version: "v1"}, |
There was a problem hiding this comment.
I don't suppose this is something we can push on elsewhere for the version to be consistent with the other protocols?
There was a problem hiding this comment.
Done — bumped to 1.0.0 for consistency with the other protocols (routing-equivalent to v1 on the platform). For context: neither value originated in this PR — v1 came from Vienna and the activity_protocol name from a pre-existing definition. Both are now defined in one central place and changed there.
There was a problem hiding this comment.
We should be consistent with the service (for both the name and the version), otherwise there's potential for confusion as things change or are updated in the future. If there were going to be a change, it should be in the service, but without that this doesn't feel like something we should be customizing.
@therealjohn , any preference?
There was a problem hiding this comment.
If the service uses v1 we should use that - and if it does, where do we file a bug to track updating it to 1.0.0 like the other protocols?
There was a problem hiding this comment.
Name: the service already renamed the union value activity_protocol → activity . AgentEndpointProtocol.ActivityValue = "activity" is the current canonical; activity_protocol is kept only as LegacyActivityProtocolValue for read back-compat, and ProtocolVersionRecord.IsActivityProtocol() matches both ( AgentEndpointProtocol.cs , HostedAgentDefinitionExtensions.cs ). So activity matches the service's canonical name, our IsActivityProtocolName mirrors its dual-spelling gate, and there's no bug to file — that rename already landed service-side.
Version: the service accepts both v1 and 1.0.0 , both routing to /api/messages ; only 2.0.0 routes to /activity/messages ( MainContainerEnvironmentConstants.SupportedActivityProtocolVersions + GetActivityProtocolContainerPath ). Our sample serves /api/messages , so 2.0.0 (the service "recommended") isn't usable; we pick 1.0.0 to match the semver form of responses / invocations . v1 is equally valid if you'd prefer the older spelling.
this PR adopts the service's renamed name ( activity ) and an accepted version ( 1.0.0 ) while keeping legacy activity_protocol / v1 read support — so it's consistent with the service, not customizing. @trangevi @therealjohn
There was a problem hiding this comment.
I don't understand why "our sample" is what we're basing this decision off of? If the service has moved to 2.0.0, I would expect we would want to as well?
- Drop Teams-specific wording from protocol/endpoint-layer comments; the Activity protocol is not unique to Teams - Use activity protocol version 1.0.0 for consistency with other protocols (routing-equivalent to v1) - Emit canonical protocol name "activity" instead of redundant "activity_protocol"; keep the legacy value accepted for back-compat - Rewrite validateProtocolSelection doc/error to state the real reason (ActivityAgentEndpoint replaces AgentEndpoint wholesale, cannot compose) - Clarify ensureActivityBot / EnsureBot / ensureTeamsChannel docs: azd provisions the Azure Bot + resource-plane Teams channel (a required connector bound to the agent identity), not the M365 Teams app - Move the embedded Teams setup guide into assets/teams_app_setup_guide.md rendered via go:embed + text/template; rendered output is byte-identical Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fc785fc to
ea1abee
Compare
jongio
left a comment
There was a problem hiding this comment.
Incremental review of the review-feedback commit (ea1abee). Changes cleanly address trangevi's feedback:
- Protocol renamed to canonical
activitywith backward-compatIsActivityProtocolName()accepting the legacyactivity_protocolvalue - Version aligned to
1.0.0semver style with routing semantics documented - Template extracted to embedded
assets/teams_app_setup_guide.md(lintable, editor-friendly) - Comments clarified: Azure Bot "Teams channel" (resource toggle) vs Teams "app" (M365 packaging/sideload) distinction is now explicit throughout
validateProtocolSelectioncomment rewritten to explain the Phase-1 scoping choice vs platform limitation- Test coverage properly updated for both old and new protocol names
No new issues. Backward compat is solid. CI lint/cspell/golangci-lint all green.
RickWinter
left a comment
There was a problem hiding this comment.
This adds native provisioning of the Azure Bot and Microsoft Teams channel for activity-protocol agents, wired into the extension's postdeploy/postdown handlers, and extends the init-from-code path to emit the same activity declaration the manifest path already produced. The shape is right. A single ResolveActivityProfile gate keeps every Teams/bot code path off non-activity deploys, the botservice client is fronted by narrow botsAPI/channelsAPI interfaces so the seven tests run against fakes, and EnsureBot is a create-or-update so redeploys stay idempotent. The protocol constant rename from "activity_protocol" to "activity" is low-risk here: the canonical constant has no non-test caller, and detection flows through IsActivityProtocolName, which still accepts the legacy value.
One thing worth resolving before merge: the postdeploy bot provisioning is placed after the optimization-reporting early returns (missing FOUNDRY_PROJECT_ENDPOINT, missing AZURE_TENANT_ID, or a credential failure each return nil with a "skipping optimization reporting" log). For an activity agent those guards silently skip the required Teams bot while deploy reports success, which also contradicts the hard-fail path immediately below where an EnsureBot error fails the deploy. The happy path is fine because provision sets both values, so this is a failure-mode and coupling concern, not a common-case bug.
Leaving Teams app packaging and sideload out of azd is the correct scope boundary, and TEAMS_APP_SETUP.md being built only from runtime values keeps it generic. Build, vet, and the botservice/project/cmd tests pass locally.
Disposition: address the postdeploy coupling before merge; the rest can proceed.
…reporting guards The postdeploy Teams bot (a required connector for activity agents) ran only after early-return guards written for best-effort optimization reporting, so a missing FOUNDRY_PROJECT_ENDPOINT / AZURE_TENANT_ID / credential silently skipped the bot while 'azd deploy' reported success — inconsistent with the EnsureBot error path that hard-fails. Resolve the activity profile first, gather the shared inputs once (no skip-vs-fail policy in the read), then let each step apply its own policy: the required bot hard-fails on a missing input; best-effort optimization reporting logs and skips. Non-activity agents are unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Activity is not exclusive: the platform models every protocol as a sibling per-protocol entry on the same endpoint, so agent.yaml just needs to advertise each selected protocol plus the BotServiceRbac scheme Activity requires. - init now composes the activity endpoint (advertises all selected protocols + appends BotServiceRbac) instead of overwriting agent_endpoint wholesale - remove validateProtocolSelection's activity-exclusive rejection - non-activity path unchanged (agent_endpoint stays nil) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drives the real init-from-code assembly (compose + schema validation) and init-from-manifest parse to prove Activity coexists with responses/invocations, while the non-activity path stays unchanged (no agent_endpoint injected). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RickWinter
left a comment
There was a problem hiding this comment.
This replaces the setup-instance-bot.ps1 / post-deploy.ps1 postdeploy scripts with native Azure Bot plus Teams-channel provisioning wired into the extension's postdeploy/postdown lifecycle, gated entirely behind an activity-protocol check so non-activity agents are untouched. The layering is right: the botservice package owns the ARM resource plane, activity_profile is the single gate, and the postdeploy input-gathering refactor cleanly separates the two policies (the required bot fails the deploy, best-effort optimization reporting only logs and skips). The narrow botsAPI/channelsAPI interfaces over armbotservice with fake-backed tests are the right call, EnsureBot idempotency and not-found-tolerant DeleteBot are handled correctly, and BotName salts on subscription plus resource group to avoid the global-uniqueness collision. The modern Go idioms (new(value), errors.AsType) are fine on 1.26.
The design point worth resolving is the activity exclusive-vs-coexistence contract. ComposeActivityAgentEndpoint is deliberately built to advertise multiple protocols on the endpoint and dedup them so activity can coexist with responses/invocations, but the description says the opposite (activity is exclusive, rejected via validateProtocolSelection). That function does not exist anywhere in the tree, and nothing prevents an agent from selecting activity plus responses, in which case postdeploy still binds a single bot to the activityProtocol endpoint while the agent is also advertised as responses. Decide which contract is intended: if activity is exclusive, the multi-protocol machinery in Compose is unreachable and can collapse to ActivityAgentEndpoint(); if coexistence is intended, the description needs correcting and the mixed case wants a test.
Separately, the description has drifted from the code in a few spots (knownProtocols is activity/1.0.0, not activity_protocol/v1; the bot is -bot-, not -bot-uai; the validateProtocolSelection exclusivity claim). Worth tidying so users and future reviewers are not misled.
Intentionally left alone and correct: the AgentProtocolActivityProtocol constant rename to "activity" is safe, since its only references are by symbol (models.go, models_test.go) and reads accept both values via IsActivityProtocolName. Disposition: address the contract question and the description drift before merge; the orphaned ActivityAgentEndpoint helper can follow. Nothing blocks; the core resource-plane logic is sound.
…l-simple # Conflicts: # cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/models.go
…ixture ActivityAgentEndpoint() was only referenced from activity_profile_test.go; every production path goes through ComposeActivityAgentEndpoint. Move it into the test as expectedActivityEndpoint() to keep the project package surface minimal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
trangevi
left a comment
There was a problem hiding this comment.
Since this last comment is in the "from code" flow, it's highly customizable and doesn't necessarily need to be a blocker in my mind.
| {Name: "activity_protocol", Version: "v1"}, | ||
| // "activity" is the canonical protocol name (legacy alias: "activity_protocol"). | ||
| // Version is a platform routing selector, not a free version string: "v1" and | ||
| // "1.0.0" route to /api/messages, "2.0.0" to /activity/messages. Our sample |
There was a problem hiding this comment.
Okay, so why are we using 1.0.0 instead of 2.0.0? I'm assuming that the service wants things moved to 2.0.0, and idk what sample this comment is referring to but I'm guessing we shouldn't be basing API decisions on a client sample?
| // deploy. It returns the written path, or "" on any failure (best-effort: never | ||
| // blocks or fails the deploy). The guide is deploy-agnostic and links to the | ||
| // official Microsoft Learn docs rather than any sample-specific scripts. | ||
| func writeTeamsSetupGuide( |
There was a problem hiding this comment.
Should all of this logic go in with the "next steps" handling? That's what that stuff is there for, right?
Closes #8955
Summary
Adds native
azdsupport for provisioning the Azure Bot and Microsoft Teams channel that front an activity-protocol (Teams) hosted agent. This replaces the previoussetup-instance-bot.ps1/post-deploy.ps1postdeploy scripts with first-class behavior wired into theazure.ai.agentsextension'spostdeploy/postdownlifecycle handlers.The end-to-end user journey is now fully native:
Non-activity agents are completely unaffected — every Teams/bot-specific code path sits behind a single gate on the agent's activity profile, so existing
responses/invocationsagents behave exactly as before.What changed (file level)
internal/cmd/listen.goensureActivityBotinpostdeployHandler,teardownActivityBotsinpostdownHandler.internal/cmd/listen_activity.go(new)ensureActivityBot(postdeploy bot provisioning),teardownActivityBots(best-effort postdown cleanup),printTeamsNextSteps,readEnvValue.internal/project/activity_profile.go(new, + test)IsActivityProtocol/ResolveActivityProfile— the single gate that detects activity opt-in (viaprotocols: activity_protocoloragent_endpoint.protocols: activity).internal/pkg/botservice/botservice.go(new, + test)EnsureBot(create/update Azure Bot),ensureTeamsChannel,DeleteBot,BotName,MessagingEndpoint. Narrow interfaces overarmbotserviceso tests use fakes (7 tests).go.mod/go.sumresourcemanager/botservice/armbotservice v1.2.0.Design
postdeployprints a short next-steps guide for those manual steps.msaAppIdis the agent instance identity client id, which only exists after the agent version is created — so bot provisioning runs inpostdeploy, after the version is active.msaAppType = SingleTenant,sku = F0,location = global,kind = azurebot.<agent-name>-bot-uai. BotService names are globally unique, sopostdowndeletes the bot to free the name for future redeploys (best-effort — failures are logged, never blockazd down).…/agents/<agent-name>/endpoint/protocols/activityProtocol?api-version=2025-05-15-preview.azd deployneither duplicates nor errors.Testing
Unit —
go build ./...,go vet ./...clean;internal/project(activity round-trip) andinternal/pkg/botservice(7 fake-backed tests) pass.Live E2E — full journey validated in a real subscription (new resource group, greenfield Foundry, North Central US):
azd ai agent initazure.yamlpreserves the activity declarations (protocols: activity_protocol,agentEndpoint.protocols: [activity],authorizationSchemes: [BotServiceRbac]).azd provisionmicrosoft.foundryprovider.azd deployactive; Azure Bot<agent>-bot-uaicreated —msaAppType=SingleTenant,msaAppId= instance identity client id,sku=F0,location=global,kind=azurebot, Teams channel enabled, messaging endpoint = pinnedactivityProtocolURL,provisioningState=Succeeded. Verified directly against ARM.azd deployazd downOut of scope / follow-ups
postdeploywrites a genericTEAMS_APP_SETUP.mdnext to the agent source with the bot id and official Microsoft Learn links.ResolveActivityProfilecurrently always resolves thesimpleuse case.azd ai agent runto launch the agent + Teams playground on localhost) — tracked in [Activity] Local testing: extend 'azd ai agent run' to launch activity agent + Teams playground on localhost #8959.quickstart-simpleas anazd ai agent inittemplate — tracked in [Activity] Ship quickstart-simple (echo) as an 'azd ai agent init' template #8960.Notes for reviewers
postdeploywrites a genericTEAMS_APP_SETUP.mdnext to the agent source. It is built only from runtime values (agent name, bot name,msaAppId) and links to the official Microsoft Learn docs for packaging and sideloading a Teams app, so it works for any activity agent (init-from-manifest or init-from-code) and is never written for non-activity deployments. A file is used rather than stdout because azd's progress UI does not surface postdeploy handler output.Update: activity-protocol support in
init-from-codeThe init-from-local-code path now supports activity-protocol agents (previously only the init-from-manifest path did). Bringing your own activity code and running
azd init(choosingactivity_protocol, or--protocol activity_protocol) now produces anazure.yamlidentical to the manifest path and fully satisfiesazd deploy.activity_protocol/v1added toknownProtocols(opt-in; no-prompt default staysresponses/2.0.0)agentEndpointwhen activity is selected — advertises every selected protocol and appendsauthorizationSchemes: [BotServiceRbac](pure-activity →protocols: [activity]), so the postdeploy bot gate fires for code-initialized agents tooazd initflow is otherwise unchanged for non-activity agentsScope: simple use case (Phase 1). Digital worker is Phase 2.
Testing & validation
Automated
azure.ai.agentsextension suite:go build ./...,go vet ./...,go test ./...— green. (The only failures locally areinternal/synthesisTestARMTemplate_MatchesBicepBuild/TestBrownfieldARMTemplate_MatchesBicepBuild, which are stale-ARM-vs-local-bicep environmental failures —templates/andinternal/synthesis/are byte-identical tomain, so unrelated to this PR.)botservice(EnsureBot create/idempotent, Teams channel, DeleteBot),activity_profile(IsActivityProtocol / ResolveActivityProfile / ActivityAgentEndpoint),init_from_code(activity_protocol flag path + coexistence with other protocols + KnownProtocolNames).Local
azd init(built viaazd x build, run through branch azd)azure.yamlcarriesagentEndpoint{protocols:[activity], authorizationSchemes:[BotServiceRbac]}+protocols:[activity_protocol/v1]--protocol activity_protocol)--protocol)protocols:[responses/2.0.0], noagentEndpoint— non-activity flow unchanged (regression check)activity_protocol+responses)protocols:[activity, responses]+authorizationSchemes:[BotServiceRbac]; activity coexists with responsesLive end-to-end (init-from-code activity project; sub
ActivityProtocol-Dev, North Central US)azd provision(2m24s, Foundry project + ACR) →azd deploy(3m7s, agent active) → postdeploy auto-provisioned the Azure Botechocode-bot-uai(SingleTenant,msaAppId= agent instance identity, F0/global, endpoint pinned to theactivityProtocolendpoint, MsTeams + WebChat + DirectLine channels enabled,provisioningState: Succeeded) →azd down --purge(1m45s, resource group deleted and bot name freed). Bot state verified directly via ARM (Microsoft.BotService/botServices, api-version 2022-09-15). The equivalent manifest-path project was validated the same way in earlier testing.Two live reference environments (Teams-verified)
To exercise both
azd ai agent initentry points, the samequickstart-echoactivity agent was deployed twice — identical in every respect except the init entry point — and both were sideloaded into Microsoft Teams and confirmed to echo replies. Both deploys use ACR remote build (docker.remoteBuild: true), not ZIP code-deploy. Subscription:ActivityProtocol-Dev, regionnorthcentralus. The flow was fully non-interactive with no manual patches (azd ai agent init->azd provision->azd deploy).azd ai agent init -m agent.manifest.yaml --deploy-mode containerazd ai agent init --deploy-mode container(from source, no manifest)echomani07031202echocode07031202rg-mani07031202-69e12725rg-code07031202-f68e547emani07031202code07031202echomani07031202-bot-<salt>echocode07031202-bot-<salt>Each deploy auto-created the Foundry project + hosted agent, the Azure Bot with the Teams channel enabled, and the
Azure AI Userrole for the instance identity. Both agents were sideloaded via a per-agent Teams app package and replied successfully in Teams, confirming the native manifest and code init paths are functionally equivalent end-to-end.Follow-up: ship
quickstart-echoas anazd ai agent inittemplateAdd the
quickstart-echo(simple activity/Teams) sample to theazd ai agent inittemplate gallery so users can scaffold it directly. Not possible yet — the sample (foundry-samples:samples/python/hosted-agents/bring-your-own/activity/echo) is not merged yet. Once it lands, ship it as a native template with the changes below. Tracked in #8960.To ship the sample as an azd template (native flow)
azure.yaml,infra/, and the old scripts (post-deploy.ps1/setup-instance-bot.ps1) —azd ai agent initscaffolds the nativeazure.yaml(foundry provider) and the extension handles the Bot + Teams channel in postdeploy.azure-ai-agentserver-coreinrequirements.txtto the same datestamp as...-activity(avoids pulling an incompatible core -> container crash -> no Teams reply).manifest.jsonname.shortso multiple installs are distinguishable.To just use the sample directly
azd ai agent init->provision->deploy(sub/location are picked in the init prompts — no manual env setup).azd deployjust emits a guide (TEAMS_APP_SETUP.md).Bottom line: templating ~= drop
azure.yaml/infra/old scripts + pin core; direct use is basically ready to run, with core-pinning the only real gotcha.